package com.bridgeintelligent.tag.webserver.workflow;

import com.bridgeintelligent.tag.constants.ExceptionCodes;
import com.bridgeintelligent.tag.constants.TagConstants;
import com.bridgeintelligent.tag.user.mgmt.pojo.User;
import com.bridgeintelligent.tag.utils.DateHelper;
import com.bridgeintelligent.tag.utils.SecurityHelper;
import com.bridgeintelligent.tag.webserver.workflow.repository.HistoryMapper;
import com.bridgeintelligent.tag.webserver.workflow.repository.InstanceMapper;
import com.bridgeintelligent.tag.webserver.workflow.repository.NodeMapper;
import com.github.pagehelper.Page;
import com.wayneleo.quickstart.framework.IDGenerator;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@AllArgsConstructor
@Transactional
public class ApproverServiceImpl implements ApproverService {
    private InstanceMapper instanceMapper;
    private NodeMapper nodeMapper;
    private HistoryMapper historyMapper;

    @Override
    public Instance fetchOne(String instanceId) {
        Instance instance = instanceMapper.findOne(instanceId);
        if (instance == null) {
            throw new WorkflowException(ExceptionCodes.WORKFLOW_20002.args(instanceId));
        }
        Node node = nodeMapper.findOne(instance.getWorkflowId(), instance.getNodeOrder());
        List<History> histories = historyMapper.findHistories(instanceId);
        instance.setNode(node);
        instance.setHistories(histories);
        return instance;
    }

    @Override
    public Page<Instance> fetchAll(String workflowId, boolean containsDeleted, Integer pageNum, Integer pageSize) {
        User user = SecurityHelper.currentUser();
        InstanceMapper.AllForApprover param = new InstanceMapper.AllForApprover()
                .setUserId(user.getUserId())
                .setContainsDeleted(containsDeleted)
                .setPageNum(pageNum)
                .setPageSize(pageSize);
        if (StringUtils.isEmpty(workflowId)) {
            for (String workflowDefinitionId : TagConstants.Workflow.values()) {
                if (SecurityHelper.containsPermission(workflowDefinitionId)) {
                    param.addApproverCode(workflowDefinitionId);
                }
            }
        } else {
            if (!SecurityHelper.containsPermission(workflowId)) {
                throw new WorkflowException((ExceptionCodes.WORKFLOW_20006.args(user.getUserId(), workflowId)));
            }
            param.addApproverCode(workflowId);
        }
        return instanceMapper.findAllForApprover(param);
    }

    @Override
    public Instance pass(String instanceId) {
        User user = SecurityHelper.currentUser();
        Instance instance = instanceMapper.findOne(instanceId);
        checkInstanceStatusIsWaitting(instance);
        List<Node> nodes = nodeMapper.findAll(instance.getWorkflowId());
        Node currentNode = null;
        if (nodes.size() >= instance.getNodeOrder()) {
            instance.setCurrentStatus(Status.PASSED.code());
            currentNode = nodes.get(nodes.size() - 1);
        } else {
            instance.setNodeOrder(instance.getNodeOrder() + 1);
            currentNode = nodes.get(instance.getNodeOrder() - 1);
        }
        instance.setUpdateDate(DateHelper.currentDateTime());
        instanceMapper.update(instance);
        History history = new History()
                .setId(IDGenerator.gen())
                .setInstanceId(instance.getId())
                .setNodeId(currentNode.getId())
                .setStatus(Status.PASSED.code())
                .setApproverId(user.getUserId())
                .setUpdateDate(DateHelper.currentDateTime())
                .setApproverName(user.getName());
        historyMapper.save(history);
        return instance;
    }

    @Override
    public Instance ccisPass(String instanceId, String approverId, String approverName) {
        Instance instance = instanceMapper.findOne(instanceId);
        checkInstanceStatusIsWaitting(instance);
        List<Node> nodes = nodeMapper.findAll(instance.getWorkflowId());
        Node currentNode = null;
        if (nodes.size() >= instance.getNodeOrder()) {
            instance.setCurrentStatus(Status.PASSED.code());
            currentNode = nodes.get(nodes.size() - 1);
        } else {
            instance.setNodeOrder(instance.getNodeOrder() + 1);
            currentNode = nodes.get(instance.getNodeOrder() - 1);
        }
        instance.setUpdateDate(DateHelper.currentDateTime());
        instanceMapper.update(instance);
        History history = new History()
                .setId(IDGenerator.gen())
                .setInstanceId(instance.getId())
                .setNodeId(currentNode.getId())
                .setStatus(Status.PASSED.code())
                .setApproverId(approverId)
                .setUpdateDate(DateHelper.currentDateTime())
                .setApproverName(approverName);
        historyMapper.save(history);
        return instance;
    }

    @Override
    public Instance reject(String instanceId, String desc) {
        User user = SecurityHelper.currentUser();
        Instance instance = instanceMapper.findOne(instanceId);
        checkInstanceStatusIsWaitting(instance);
        Node node = nodeMapper.findOne(instance.getWorkflowId(), instance.getNodeOrder());
        instance.setNodeOrder(1).setCurrentStatus(Status.REJECTED.code());
        instance.setDesc(desc);
        instance.setUpdateDate(DateHelper.currentDateTime());
        instanceMapper.update(instance);
        History history = new History()
                .setId(IDGenerator.gen())
                .setInstanceId(instance.getId())
                .setNodeId(node.getId())
                .setStatus(Status.REJECTED.code())
                .setApproverId(user.getUserId())
                .setApproverName(user.getName())
                .setUpdateDate(DateHelper.currentDateTime())
                .setDesc(desc);
        historyMapper.save(history);
        return instance;
    }

    @Override
    public Instance ccisReject(String instanceId, String desc, String approverId, String approverName) {
        Instance instance = instanceMapper.findOne(instanceId);
        checkInstanceStatusIsWaitting(instance);
        Node node = nodeMapper.findOne(instance.getWorkflowId(), instance.getNodeOrder());
        instance.setNodeOrder(1).setCurrentStatus(Status.REJECTED.code());
        instance.setDesc(desc);
        instance.setUpdateDate(DateHelper.currentDateTime());
        instanceMapper.update(instance);
        History history = new History()
                .setId(IDGenerator.gen())
                .setInstanceId(instance.getId())
                .setNodeId(node.getId())
                .setStatus(Status.REJECTED.code())
                .setApproverId(approverId)
                .setApproverName(approverName)
                .setUpdateDate(DateHelper.currentDateTime())
                .setDesc(desc);
        historyMapper.save(history);
        return instance;
    }

    @Override
    public List<History> findOperationRecord(String resourceId) {
        return historyMapper.findOperationRecord(resourceId);
    }

    private void checkInstanceStatusIsWaitting(Instance instance) {
        if (instance.getCurrentStatus() != Status.WAITTING.code()) {
            throw new WorkflowException(ExceptionCodes.WORKFLOW_20005.args(instance.getId()));
        }
    }
}
